﻿using System;
using System.Collections.Generic;
using System.Data;

using NUnit.Framework;

namespace Pvax.Data.Tests
{
    /// <summary>
    /// This the <see cref="DbConnectionExtender"/> test uses <see cref="Person"/> and <see cref="Phone"/>
    /// classes.
    /// </summary>
    public abstract class TestDbConnectionExtender: TestBase
    {
        protected IDbConnection connection;

        // Must initialize the connection
        protected abstract void InitializeConnection();

        [SetUp]
        public void Init()
        {
            InitializeConnection();
            connection.Open();
        }

        [TearDown]
        public void Done()
        {
            ExecuteSql(connection, "DELETE FROM Persons WHERE Id=42");
            ExecuteSql(connection, "DELETE FROM Phones WHERE Id=100");
            connection.Close();
            connection = null;
        }

        [Test]
        public void TestSelectAllPersons()
        {
            List<Person> people = new List<Person>();
            foreach(var person in connection.GetAll<Person>())
                people.Add(person);
            Assert.AreEqual(4, people.Count);
            Assert.AreEqual(1, people[0].Id);
            Assert.AreEqual(2, people[1].Id);
        }

        [Test]
        public void TestSelectAllPhones()
        {
            List<Phone> phones = new List<Phone>();
            foreach(var phone in connection.GetAll<Phone>())
                phones.Add(phone);
            Assert.AreEqual(3, phones.Count);
            Assert.AreEqual(1, phones[0].Id);
            Assert.AreEqual(2, phones[1].Id);
            Assert.AreEqual(3, phones[2].Id);
            Assert.AreEqual(1, phones[0].PersonId);
            Assert.AreEqual(1, phones[1].PersonId);
            Assert.AreEqual(2, phones[2].PersonId);
        }

        [Test]
        public void TestSelectPersonById()
        {
            var person = connection.Get<Person, long>(2);
            Assert.AreEqual("Ender", person.FirstName);
        }

        [Test]
        public void TestSelectPhoneById()
        {
            var phone = connection.Get<Phone, long>(2);
            Assert.AreEqual(811, phone.AreaCode);
        }

        [Test]
        public void TestSelectPeopleByFirstName()
        {
            List<Person> people = new List<Person>();
            foreach(var person in connection.GetBy<Person>("FirstName", "Ender"))
                people.Add(person);
            Assert.AreEqual(1, people.Count);
            Assert.AreEqual("Wiggin", people[0].LastName);
        }

        [Test]
        public void TestSelectPhonesByAreaCode()
        {
            List<Phone> phones = new List<Phone>();
            foreach(var phone in connection.GetBy<Phone>("AreaCode", 811))
                phones.Add(phone);
            Assert.AreEqual(2, phones.Count);
        }

        [Test]
        public void TestInsertPersonWithSelect()
        {
            var person = new Person()
            {
                Id = 42,
                FirstName = "Douglas",
                MiddleName = String.Empty,
                LastName = "Adams"
            };
            connection.Add(person);
            person = null;
            person = connection.Get<Person, long>(42);
            Assert.AreEqual("Douglas", person.FirstName);
            Assert.AreEqual("Adams", person.LastName);
        }

        [Test]
        public void TestInsertPhoneWithSelect()
        {
            var phone = new Phone()
            {
                Id = 100,
                CountryCode = 1,
                AreaCode = 555,
                Number = "4325671"
            };
            connection.Add(phone);
            phone = null;
            phone = connection.Get<Phone, long>(100);
            Assert.AreEqual("4325671", phone.Number);
            Assert.AreEqual(555, phone.AreaCode);
        }

        [Test]
        public void TestUpdatePerson()
        {
            // As in TestSelectPersonById()
            var person = connection.Get<Person, long>(2);
            Assert.AreEqual("Ender", person.FirstName);
            person.FirstName = "Michael";
            person.MiddleName = String.Empty;
            person.LastName = "Chrichton";
            connection.Put<Person>(person);
            person = connection.Get<Person, long>(2);
            Assert.AreEqual("Michael", person.FirstName);
            Assert.AreEqual(String.Empty, person.MiddleName);
            Assert.AreEqual("Chrichton", person.LastName);
        }

        [Test]
        public void TestUpdatePhone()
        {
            // As in TestSelectPhoneById()
            var phone = connection.Get<Phone, long>(2);
            Assert.AreEqual(811, phone.AreaCode);
            phone.CountryCode = 7;
            phone.AreaCode = 312;
            phone.Number = "9296739";
            connection.Put<Phone>(phone);
            phone = connection.Get<Phone, long>(2);
            Assert.AreEqual(7, phone.CountryCode);
            Assert.AreEqual(312, phone.AreaCode);
            Assert.AreEqual("9296739", phone.Number);
        }

        [Test]
        public void TestDeletePersonById()
        {
            ExecuteSql(connection, "INSERT INTO Persons (Id) VALUES (42)");
            var person = connection.Get<Person, long>(42);
            connection.Remove(person);
            person = connection.Get<Person, long>(42);
            Assert.IsNull(person);
        }

        [Test]
        public void TestDeletePhoneById()
        {
            ExecuteSql(connection, "INSERT INTO Phones (Id,PersonId,CountryCode,AreaCode) VALUES (42,1,0,0)");
            var phone = connection.Get<Phone, long>(42);
            connection.Remove(phone);
            phone = connection.Get<Phone, long>(42);
            Assert.IsNull(phone);
        }

        [Test]
        public void TestDeletePerson()
        {
            ExecuteSql(connection, "INSERT INTO Persons (Id) VALUES (42)");
            var person = new Person()
            {
                Id = 42
            };
            connection.Remove(person);
            person = connection.Get<Person, long>(42);
            Assert.IsNull(person);
        }

        [Test]
        public void TestDeletePhone()
        {
            ExecuteSql(connection, "INSERT INTO Phones (Id,PersonId,CountryCode,AreaCode) VALUES (42,1,0,0)");
            var phone = new Phone()
            {
                Id = 42
            };
            connection.Remove(phone);
            phone = connection.Get<Phone, long>(42);
            Assert.IsNull(phone);
        }        
    }
}
